from loguru import logger
import time
import asyncio
from decimal import Decimal
from typing import Dict, List, Optional
from logs import setup_order_logger
from database_manager import DatabaseManager
from exchange_manager import ExchangeManager

class OrderExecutor:
    """
    订单执行器
    负责所有订单相关的操作，包括下单、撤单、查询等
    """
    def __init__(self, exchange_manager: ExchangeManager, db_manager: Optional[DatabaseManager] = None):
        self.exchange_manager = exchange_manager
        self.db_manager = db_manager or DatabaseManager()
        self.logger = setup_order_logger()
        self.depth_ratio = Decimal('1.5')  # 盘口深度比例要求

    async def check_order_book_depth(self, exchange_id: str, symbol: str, side: str, required_volume: Decimal) -> bool:
        """
        检查订单簿深度是否满足要求
        
        Args:
            exchange_id: 交易所ID
            symbol: 交易对
            side: 买卖方向 (buy/sell)
            required_volume: 所需交易量
            
        Returns:
            bool: 深度是否满足要求
        """
        try:
            exchange = self.exchange_manager.get_exchange(exchange_id)
            if not exchange:
                self.logger.error(f"交易所 {exchange_id} 不存在")
                return False
                
            order_book = await exchange.fetch_order_book(symbol)
            if not order_book:
                return False
                
            # 计算所需深度
            required_depth = required_volume * self.depth_ratio
            
            # 检查深度
            if side == 'buy':
                # 检查卖单深度
                total_volume = Decimal('0')
                for price, volume in order_book['asks']:
                    total_volume += Decimal(str(volume))
                    if total_volume >= required_depth:
                        return True
            else:
                # 检查买单深度
                total_volume = Decimal('0')
                for price, volume in order_book['bids']:
                    total_volume += Decimal(str(volume))
                    if total_volume >= required_depth:
                        return True
                        
            self.logger.warning(f"{exchange_id} {symbol} {side}方向深度不足，需要: {required_depth}，实际: {total_volume}")
            return False
            
        except Exception as e:
            self.logger.error(f"检查订单簿深度时出错: {str(e)}")
            return False

    async def create_order(self, exchange_id: str, symbol: str, order_type: str, side: str, 
                         amount: Decimal, price: Optional[Decimal] = None, leverage: int = 1) -> Optional[Dict]:
        """
        创建订单
        
        Args:
            exchange_id: 交易所ID
            symbol: 交易对
            order_type: 订单类型 (market/limit)
            side: 买卖方向 (buy/sell)
            amount: 交易量
            price: 价格 (市价单可为None)
            leverage: 杠杆倍数
            
        Returns:
            Dict: 订单信息
        """
        try:
            exchange = self.exchange_manager.get_exchange(exchange_id)
            if not exchange:
                self.logger.error(f"交易所 {exchange_id} 不存在")
                return None
                
            # 设置杠杆倍数
            try:
                await asyncio.to_thread(exchange.set_leverage, leverage, symbol)
                self.logger.info(f"设置杠杆倍数成功 - 交易所: {exchange_id}, 交易对: {symbol}, 杠杆: {leverage}x")
            except Exception as e:
                self.logger.error(f"设置杠杆倍数失败: {str(e)}")
                return None
                
            # 准备订单参数
            params = {
                'type': order_type,
                'side': side,
                'amount': float(amount),
            }
            
            # 如果是限价单，添加价格参数
            if order_type == 'limit' and price is not None:
                params['price'] = float(price)
                
            # 下单
            order = await asyncio.to_thread(exchange.create_order, symbol, order_type, side, float(amount), float(price) if price else None)
            
            # 保存订单信息到数据库
            order_info = {
                'exchange_id': exchange_id,
                'symbol': symbol,
                'order_id': order['id'],
                'order_type': order_type,
                'side': side,
                'amount': float(amount),
                'price': float(price) if price else None,
                'leverage': leverage,
                'status': order['status'],
                'create_time': time.time()
            }
            
            self.db_manager.save_order(order_info)
            self.logger.info(f"订单已保存到数据库 - {order['id']}")
            
            self.logger.info(f"下单成功 - 交易所: {exchange_id}, 交易对: {symbol}, 方向: {side}, 类型: {order_type}, 杠杆: {leverage}x")
            return order
            
        except Exception as e:
            self.logger.error(f"下单失败: {str(e)}")
            return None

    async def execute_order(self, exchange_id: str, symbol: str, order_type: str, side: str, amount: float, price: Optional[float] = None) -> bool:
        """
        执行订单
        
        Args:
            exchange_id: 交易所ID
            symbol: 交易对
            order_type: 订单类型
            side: 买卖方向
            amount: 数量
            price: 价格（市价单可为None）
            
        Returns:
            bool: 是否成功执行
        """
        try:
            exchange = self.exchange_manager.get_exchange(exchange_id)
            if not exchange:
                self.logger.error(f"交易所 {exchange_id} 不存在")
                return False

            # 直接使用异步方法
            order = await exchange.create_order(
                symbol=symbol,
                type=order_type,
                side=side,
                amount=float(amount),
                price=float(price) if price else None
            )
            
            self.logger.info(f"订单执行成功: {order}")
            return True
            
        except Exception as e:
            self.logger.error(f"执行订单失败: {str(e)}")
            return False

    async def cancel_order(self, exchange_id: str, order_id: str, symbol: str) -> bool:
        """
        取消订单
        
        Args:
            exchange_id: 交易所ID
            order_id: 订单ID
            symbol: 交易对
            
        Returns:
            bool: 是否成功取消
        """
        try:
            exchange = self.exchange_manager.get_exchange(exchange_id)
            if not exchange:
                self.logger.error(f"交易所 {exchange_id} 不存在")
                return False

            # 直接使用异步方法
            result = await exchange.cancel_order(order_id, symbol)
            
            self.logger.info(f"订单取消成功: {result}")
            return True
            
        except Exception as e:
            self.logger.error(f"取消订单失败: {str(e)}")
            return False

    async def get_order_status(self, exchange_id: str, order_id: str, symbol: str) -> Optional[Dict]:
        """
        获取订单状态
        
        Args:
            exchange_id: 交易所ID
            order_id: 订单ID
            symbol: 交易对
            
        Returns:
            Dict: 订单状态信息
        """
        try:
            exchange = self.exchange_manager.get_exchange(exchange_id)
            if not exchange:
                self.logger.error(f"交易所 {exchange_id} 不存在")
                return None
                
            # 获取订单状态
            order = await asyncio.to_thread(exchange.fetch_order, order_id, symbol)
            
            # 更新数据库中的订单状态
            if order:
                self.db_manager.update_order_status(
                    order_id,
                    order['status'],
                    time.time(),
                    float(order.get('price', 0)),
                    float(order.get('filled', 0))
                )
            
            return order
            
        except Exception as e:
            self.logger.error(f"获取订单状态失败: {str(e)}")
            return None

    async def execute_arbitrage_trade(self, opportunity: Dict) -> bool:
        """
        执行套利交易
        
        Args:
            opportunity: 套利机会信息
            
        Returns:
            bool: 是否成功执行交易
        """
        try:
            symbol = opportunity['symbol']
            sell_exchange = opportunity['sell_exchange']
            buy_exchange = opportunity['buy_exchange']
            sell_price = Decimal(str(opportunity['sell_price']))
            buy_price = Decimal(str(opportunity['buy_price']))
            volume = Decimal(str(opportunity['volume']))
            leverage = opportunity.get('leverage', 1)
            
            self.logger.info(f"准备执行套利交易 - {symbol}")
            self.logger.info(f"在 {sell_exchange} 以 {sell_price} 卖出")
            self.logger.info(f"在 {buy_exchange} 以 {buy_price} 买入")
            self.logger.info(f"交易量: {volume}, 杠杆: {leverage}x")
            
            # 检查盘口深度
            sell_depth_ok = await self.check_order_book_depth(sell_exchange, symbol, 'sell', volume)
            buy_depth_ok = await self.check_order_book_depth(buy_exchange, symbol, 'buy', volume)
            
            if not sell_depth_ok or not buy_depth_ok:
                self.logger.warning("盘口深度不足，取消交易")
                self.db_manager.update_arbitrage_opportunity_status(
                    opportunity['id'], 
                    'DEPTH_INSUFFICIENT',
                    f"盘口深度不足: 卖出={sell_depth_ok}, 买入={buy_depth_ok}"
                )
                return False
            
            # 创建卖出订单
            sell_order = await self.create_order(
                exchange_id=sell_exchange,
                symbol=symbol,
                order_type="limit",
                side="sell",
                amount=volume,
                price=sell_price,
                leverage=leverage
            )
            
            if not sell_order:
                self.logger.error("创建卖出订单失败")
                self.db_manager.update_arbitrage_opportunity_status(
                    opportunity['id'], 
                    'SELL_ORDER_FAILED',
                    "创建卖出订单失败"
                )
                return False
                
            self.logger.info(f"卖出订单创建成功: {sell_order['id']}")
            
            # 创建买入订单
            buy_order = await self.create_order(
                exchange_id=buy_exchange,
                symbol=symbol,
                order_type="limit",
                side="buy",
                amount=volume,
                price=buy_price,
                leverage=leverage
            )
            
            if not buy_order:
                self.logger.error("创建买入订单失败，尝试取消卖出订单")
                await self.cancel_order(sell_exchange, sell_order['id'], symbol)
                self.db_manager.update_arbitrage_opportunity_status(
                    opportunity['id'], 
                    'BUY_ORDER_FAILED',
                    "创建买入订单失败"
                )
                return False
                
            self.logger.info(f"买入订单创建成功: {buy_order['id']}")
            
            # 保存套利订单到数据库
            arbitrage_order = {
                'symbol': symbol,
                'sell_exchange': sell_exchange,
                'buy_exchange': buy_exchange,
                'sell_price': float(sell_price),
                'buy_price': float(buy_price),
                'volume': float(volume),
                'leverage': leverage,
                'sell_order_id': sell_order['id'],
                'buy_order_id': buy_order['id'],
                'status': 'OPEN',
                'create_time': time.time(),
                'profit': float((buy_price - sell_price) * volume),
                'opportunity_id': opportunity['id']
            }
            
            self.db_manager.save_arbitrage_order(arbitrage_order)
            self.logger.info(f"套利订单已保存到数据库，预期利润: {arbitrage_order['profit']:.8f}")
            
            # 更新套利机会状态
            self.db_manager.update_arbitrage_opportunity_status(
                opportunity['id'], 
                'EXECUTED',
                f"订单已执行: 卖出={sell_order['id']}, 买入={buy_order['id']}"
            )
            
            return True
            
        except Exception as e:
            self.logger.error(f"执行套利交易时出错: {str(e)}")
            if 'id' in opportunity:
                self.db_manager.update_arbitrage_opportunity_status(
                    opportunity['id'], 
                    'ERROR',
                    f"执行错误: {str(e)}"
                )
            return False 